Feature: Kontaktformular-Modal ersetzt mailto-Links, speichert in PocketBase inquiries

This commit is contained in:
rene 2026-05-17 17:25:10 +02:00
parent cfdb52643f
commit 829a4b6e0e
2 changed files with 176 additions and 6 deletions

View file

@ -29,7 +29,49 @@
sonstiges: iconTherm
};
let activeView = $state<'dashboard' | 'protokoll' | 'stationen'>('dashboard');
let activeView = $state<'dashboard' | 'protokoll' | 'stationen'>('dashboard');
// Kontaktformular
let showModal = $state(false);
let modalPlan = $state('');
let formName = $state('');
let formCompany = $state('');
let formEmail = $state('');
let formPhone = $state('');
let formMsg = $state('');
let formSending = $state(false);
let formDone = $state(false);
let formError = $state('');
function openModal(plan = '') {
modalPlan = plan;
formDone = false;
formError = '';
showModal = true;
}
function closeModal() { showModal = false; }
async function submitForm() {
if (!formName.trim() || !formEmail.trim()) { formError = 'Bitte Name und E-Mail ausfüllen.'; return; }
formSending = true; formError = '';
try {
await pb.collection('inquiries').create({
name: formName.trim(),
company: formCompany.trim(),
email: formEmail.trim(),
phone: formPhone.trim(),
message: formMsg.trim(),
plan: modalPlan
});
formDone = true;
formName = formCompany = formEmail = formPhone = formMsg = '';
} catch {
formError = 'Fehler beim Senden. Bitte direkt an hallo@checkflo.de schreiben.';
} finally {
formSending = false;
}
}
let liveLogs = $state<any[]>([]);
let liveStats = $state({ total: 0, ok: 0, warn: 0, crit: 0 });
let lastUpdate = $state('');
@ -127,7 +169,7 @@
Und Ihre Kunden sehen nur Ihr Logo.
</p>
<div class="hero-actions">
<a href="mailto:hallo@checkflo.de" class="btn-primary">Kostenlose Demo vereinbaren</a>
<button class="btn-primary" onclick={() => openModal()}>Kostenlose Demo vereinbaren</button>
<a href="#funktionen" class="btn-ghost">So funktioniert es ↓</a>
</div>
</div>
@ -318,7 +360,7 @@
<li>✓ PDF-Export für Ihre Kunden</li>
<li>✓ Offline-fähige PWA</li>
</ul>
<a href="mailto:hallo@checkflo.de?subject=Basic White-Label Anfrage" class="btn-plan">Demo vereinbaren</a>
<button class="btn-plan" onclick={() => openModal('Basic White-Label')}>Demo vereinbaren</button>
</div>
<div class="plan plan-featured">
<div class="plan-badge">Empfohlen</div>
@ -333,7 +375,7 @@
<li>✓ Dynamisches Branding je Kunde</li>
<li>✓ Prioritäts-Support</li>
</ul>
<a href="mailto:hallo@checkflo.de?subject=Pro White-Label Anfrage" class="btn-plan btn-plan-featured">Demo vereinbaren</a>
<button class="btn-plan btn-plan-featured" onclick={() => openModal('Pro White-Label')}>Demo vereinbaren</button>
</div>
<div class="plan">
<div class="plan-name">Enterprise</div>
@ -347,7 +389,7 @@
<li>✓ Individuelle Entwicklung</li>
<li>✓ Schulung & Onboarding</li>
</ul>
<a href="mailto:hallo@checkflo.de?subject=Enterprise Anfrage" class="btn-plan">Angebot anfragen</a>
<button class="btn-plan" onclick={() => openModal('Enterprise')}>Angebot anfragen</button>
</div>
</div>
<p class="pricing-note">Keine Einrichtungsgebühr · Monatlich kündbar · Alle Pläne inkl. Updates</p>
@ -359,10 +401,64 @@
<div class="container">
<h2>Bieten Sie Ihren Kunden eine eigene HACCP-App an.</h2>
<p>Für Prüfbetriebe, Ingenieurbüros und Facility-Management-Firmen.</p>
<a href="mailto:hallo@checkflo.de" class="btn-primary btn-large">Kostenlose Demo vereinbaren</a>
<button class="btn-primary btn-large" onclick={() => openModal()}>Kostenlose Demo vereinbaren</button>
</div>
</section>
<!-- KONTAKT-MODAL -->
{#if showModal}
<div class="modal-overlay" onclick={closeModal} role="dialog" aria-modal="true">
<div class="modal" onclick={(e) => e.stopPropagation()}>
{#if formDone}
<div class="modal-success">
<div class="modal-success-icon"></div>
<h3>Vielen Dank!</h3>
<p>Wir melden uns innerhalb von 24 Stunden bei Ihnen.</p>
<button class="btn-primary" onclick={closeModal}>Schließen</button>
</div>
{:else}
<div class="modal-header">
<div>
<h3>Demo vereinbaren</h3>
{#if modalPlan}<p class="modal-plan">Plan: <strong>{modalPlan}</strong></p>{/if}
</div>
<button class="modal-close" onclick={closeModal}>✕</button>
</div>
<form onsubmit={(e) => { e.preventDefault(); submitForm(); }}>
<div class="modal-row">
<div class="modal-field">
<label for="m-name">Name *</label>
<input id="m-name" type="text" placeholder="Max Mustermann" bind:value={formName} />
</div>
<div class="modal-field">
<label for="m-company">Firma</label>
<input id="m-company" type="text" placeholder="Muster Prüfdienste GmbH" bind:value={formCompany} />
</div>
</div>
<div class="modal-row">
<div class="modal-field">
<label for="m-email">E-Mail *</label>
<input id="m-email" type="email" placeholder="max@beispiel.de" bind:value={formEmail} />
</div>
<div class="modal-field">
<label for="m-phone">Telefon</label>
<input id="m-phone" type="tel" placeholder="+49 123 456789" bind:value={formPhone} />
</div>
</div>
<div class="modal-field">
<label for="m-msg">Nachricht (optional)</label>
<textarea id="m-msg" rows="3" placeholder="Wie viele Kunden betreuen Sie? Welche Branche?" bind:value={formMsg}></textarea>
</div>
{#if formError}<p class="modal-error">{formError}</p>{/if}
<button type="submit" class="btn-primary" disabled={formSending}>
{formSending ? 'Wird gesendet…' : 'Anfrage senden'}
</button>
</form>
{/if}
</div>
</div>
{/if}
<!-- FOOTER -->
<footer>
<div class="container">
@ -835,6 +931,44 @@
padding: 1.5rem 2rem;
border-top: 1px solid #f0f0f0;
}
/* MODAL */
.modal-overlay {
position: fixed; inset: 0;
background: rgba(11,16,35,0.7);
display: flex; align-items: center; justify-content: center;
z-index: 100; padding: 1rem;
backdrop-filter: blur(4px);
}
.modal {
background: #fff; border-radius: 16px;
padding: 2rem; width: 100%; max-width: 540px;
box-shadow: 0 24px 60px rgba(0,0,0,0.3);
}
.modal-header { display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 1.5rem; }
.modal-header h3 { font-size: 1.3rem; font-weight: 800; color: #0B1023; }
.modal-plan { font-size: 0.85rem; color: #888; margin-top: 0.2rem; }
.modal-close { background: none; border: none; font-size: 1.2rem; color: #aaa; cursor: pointer; padding: 0.25rem; }
.modal-close:hover { color: #0B1023; }
.modal-row { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; }
.modal-field { display: flex; flex-direction: column; gap: 0.35rem; margin-bottom: 1rem; }
.modal-field label { font-size: 0.85rem; font-weight: 600; color: #444; }
.modal-field input, .modal-field textarea {
border: 1.5px solid #ddd; border-radius: 8px;
padding: 0.65rem 0.9rem; font-size: 0.95rem;
font-family: inherit; resize: vertical;
transition: border-color 0.15s;
}
.modal-field input:focus, .modal-field textarea:focus { outline: none; border-color: #F97316; }
.modal-error { color: #dc2626; font-size: 0.85rem; background: #fef2f2; padding: 0.6rem; border-radius: 8px; margin-bottom: 1rem; }
.modal-success { text-align: center; padding: 1rem 0; }
.modal-success-icon { width: 3.5rem; height: 3.5rem; background: #dcfce7; color: #16a34a; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 1.5rem; margin: 0 auto 1rem; }
.modal-success h3 { font-size: 1.3rem; font-weight: 800; color: #0B1023; margin-bottom: 0.5rem; }
.modal-success p { color: #666; margin-bottom: 1.5rem; }
@media (max-width: 480px) { .modal-row { grid-template-columns: 1fr; } }
footer .container {
display: flex;
justify-content: space-between;

36
scripts/setup-inquiries.sh Executable file
View file

@ -0,0 +1,36 @@
#!/bin/bash
# Legt die inquiries-Collection für Kontaktanfragen an
set -euo pipefail
PB_URL="${PB_URL:-https://api.checkflo.de}"
if [ -z "${PB_EMAIL:-}" ] || [ -z "${PB_PASSWORD:-}" ]; then
echo "Aufruf: PB_EMAIL=... PB_PASSWORD=... ./setup-inquiries.sh"; exit 1
fi
TOKEN=$(curl -sf -X POST "$PB_URL/api/collections/_superusers/auth-with-password" \
-H "Content-Type: application/json" \
-d "{\"identity\":\"$PB_EMAIL\",\"password\":\"$PB_PASSWORD\"}" | jq -r '.token')
curl -sf -X POST "$PB_URL/api/collections" \
-H "Authorization: $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "inquiries",
"type": "base",
"fields": [
{"name": "name", "type": "text", "required": true},
{"name": "company", "type": "text"},
{"name": "email", "type": "email", "required": true},
{"name": "phone", "type": "text"},
{"name": "message", "type": "text"},
{"name": "plan", "type": "text"}
],
"listRule": null,
"viewRule": null,
"createRule": "",
"updateRule": null,
"deleteRule": null
}' | jq .name
echo "✓ inquiries Collection angelegt"