Feature: Kontaktformular-Modal ersetzt mailto-Links, speichert in PocketBase inquiries
This commit is contained in:
parent
cfdb52643f
commit
829a4b6e0e
2 changed files with 176 additions and 6 deletions
|
|
@ -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
36
scripts/setup-inquiries.sh
Executable 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"
|
||||
Loading…
Add table
Add a link
Reference in a new issue